package com.dps.recommend.utils;


import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @author ysl
 */
public class DateUtil {
    private static DateFormat partitionDateFormat = new SimpleDateFormat(
            "yyyy-MM-dd");
    private static DateFormat shortDateFormat = new SimpleDateFormat("yyyyMMdd");
    private static DateFormat longDateFormat = new SimpleDateFormat(
            "yyyyMMddHHmmss");

    private static DateFormat preciseDateFormat = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");

    private static DateFormat minuteDateFormat = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm");

    private static DateFormat monthDateFormat = new SimpleDateFormat(
            "yyyy-MM");

    private static DateFormat timeFormatWithoutDate = new SimpleDateFormat(
            "HH:mm:ss");

    private static DateFormat msDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    private static DateFormat mhDateFormat = new SimpleDateFormat("HH");
    private static DateFormat mmDateFormat = new SimpleDateFormat("HH:mm");

    private static final DateFormat dayGMTDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    public static double getDifferentTimeMinutes(String dateStr) {
        try {
            Date date2 = preciseDateFormat.parse(dateStr);
            Date date1 = new Date();
            return (date1.getTime() - date2.getTime()) / (1000.0 * 60);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0.0;
    }

    public static String getCurrentTimeSeconds() {
        Date date = new Date();
        return preciseDateFormat.format(date);
    }


    public synchronized static Date parseDateString(String dateStr) {
        int length = dateStr.length();
        DateFormat format;

        if (7 == length) {
            format = monthDateFormat;
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (8 == length) {
            format = shortDateFormat;
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (14 == length) {
            format = longDateFormat;
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (10 == length) {
            format = partitionDateFormat;
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }

            format = new SimpleDateFormat("yyyy/MM/dd");
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (19 == length) {
            format = preciseDateFormat;
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (21 == length) {
            format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (16 == length) {
            try {
                return minuteDateFormat.parse(dateStr);
            } catch (ParseException e) {

            }
        } else if (23 == length) {
            format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            try {
                return format.parse(dateStr);
            } catch (ParseException e) {

            }
        }

        throw new RuntimeException("can not parse date string :" + dateStr);
    }

    public synchronized static Date parseDateStringTwice(String dateStr) {
        try {
            Date date = preciseDateFormat.parse(dateStr);
            return date;
        } catch (Exception e) {
        }

        try {
            Date date = partitionDateFormat.parse(dateStr);
            return date;
        } catch (Exception e) {
        }
        throw new RuntimeException("can not parse date string :" + dateStr);
    }

    public synchronized static String getPartitionString(Date date) {
        return partitionDateFormat.format(date);
    }

    public synchronized static String getShortDateString(Date date) {
        return shortDateFormat.format(date);
    }

    public synchronized static String getLongDateString(Date date) {
        return longDateFormat.format(date);
    }

    public synchronized static String getPreciseDateString(Date date) {
        return preciseDateFormat.format(date);
    }

    public synchronized static String getMinuteDateString(Date date) {
        return minuteDateFormat.format(date) + ":00";
    }

    public synchronized static String getMinuteDateString2(Date date) {
        return minuteDateFormat.format(date);
    }

    public synchronized static String getMonthDateString(Date date) {
        return monthDateFormat.format(date);
    }

    public synchronized static String getMsDateString(Date date) {
        return msDateFormat.format(date);
    }

    public synchronized static String getMhDateString(Date date) {
        return mhDateFormat.format(date);
    }

    public synchronized static String getMmDateString(Date date) {
        return mmDateFormat.format(date);
    }

    public synchronized static String getTimeStringWithoutDate(Date date) {
        return timeFormatWithoutDate.format(date);
    }

    public synchronized static java.sql.Date toSQLDate(Date date) {
        return new java.sql.Date(date.getTime());
    }

    public synchronized static java.sql.Timestamp toSQLTimestamp(
            String dateString) {
        return java.sql.Timestamp.valueOf(dateString);
    }

    public synchronized static java.sql.Date toSQLDate(String dateString) {
        Date date = parseDateString(dateString);
        return new java.sql.Date(date.getTime());
    }

    public synchronized static Date getOffsetDate(Date currentDate,
                                                  int offsetDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.DATE, offsetDate);
        return calendar.getTime();
    }

    public synchronized static String getOffsetDatePartitionString(
            Date currentDate, int offsetDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.DATE, offsetDate);
        return partitionDateFormat.format(calendar.getTime());
    }

    public synchronized static String getOffsetDateShortString(
            Date currentDate, int offsetDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.DATE, offsetDate);
        return shortDateFormat.format(calendar.getTime());
    }

    public synchronized static Date getOffsetHour(Date currentDate,
                                                  int offsetHour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.HOUR, offsetHour);
        return calendar.getTime();
    }

    public synchronized static String getOffsetHour(String dateStr,
                                                    int offsetHour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parseDateString(dateStr));
        calendar.add(Calendar.HOUR, offsetHour);
        return getPreciseDateString(calendar.getTime());
    }

    public synchronized static String getOffsetMinute(String dateStr,
                                                      int offsetMinute) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parseDateString(dateStr));
        calendar.add(Calendar.MINUTE, offsetMinute);
        return getPreciseDateString(calendar.getTime());
    }

    public synchronized static String getOffsetMonthPartitionString(
            String dateStr, int offsetMonth) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parseDateString(dateStr));
        calendar.add(Calendar.MONTH, offsetMonth);
        return partitionDateFormat.format(calendar.getTime());
    }


    public synchronized static String getOffsetDayPartitionString(
            String dateStr, int offsetDay) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parseDateString(dateStr));
        calendar.add(Calendar.DATE, offsetDay);
        return partitionDateFormat.format(calendar.getTime());
    }

    public synchronized static int getYearFromDateStr(String dateStr) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parseDateString(dateStr));
        return calendar.get(Calendar.YEAR);

    }

    public synchronized static int daysBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        Long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Math.abs(between_days.intValue());
    }

    public synchronized static int hoursBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        Long between_hours = (time2 - time1) / (1000 * 60 * 60);
        return Math.abs(between_hours.intValue());
    }

    public synchronized static int minutesBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        Long between_minutes = (time2 - time1) / (1000 * 60);
        return Math.abs(between_minutes.intValue());
    }

    public synchronized static int secondsBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        Long between_minutes = (time2 - time1) / (1000);
        return Math.abs(between_minutes.intValue());
    }

    public synchronized static Date lastSunday(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            int day = calendar.get(Calendar.DATE);
            calendar.set(Calendar.DATE, day - 1);
            calendar.setTime(calendar.getTime());
        }
        calendar.set(Calendar.DAY_OF_WEEK, 1);
        return calendar.getTime();
    }

    public synchronized static Date getOffsetSunday(int offset) {
        Date sunday = lastSunday(new Date());
        if (1 < offset) {
            sunday = DateUtil.getOffsetDate(sunday, (offset - 1) * 7 * (-1));
        }
        return sunday;
    }

    public synchronized static String getDataFormat(DateFormat format, Date date) {
        return format.format(date);
    }

    public synchronized static Date getRecentDay(int num) {
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -num);
        date = calendar.getTime();
        return date;
    }

    public synchronized static Date getRecentDay(int num, Date curtDate) {
        return getRelativeDay(-num, curtDate);
    }

    public synchronized static Date getRelativeDay(int num, Date curtDate) {
        try {
            curtDate = partitionDateFormat.parse(partitionDateFormat
                    .format(curtDate) + " 00:00:00");
        } catch (ParseException e) {
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curtDate);
        calendar.add(Calendar.DAY_OF_MONTH, num);
        curtDate = calendar.getTime();
        return curtDate;
    }

    public synchronized static Date getRelativeDay(int num, int calendarDayNum,
                                                   Date curtDate) {
        try {
            curtDate = partitionDateFormat.parse(partitionDateFormat
                    .format(curtDate) + " 00:00:00");
        } catch (ParseException e) {
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curtDate);
        calendar.add(calendarDayNum, num);
        curtDate = calendar.getTime();
        return curtDate;
    }

    public synchronized static Date getNextDay(Date curtDate) {
        try {
            curtDate = partitionDateFormat.parse(partitionDateFormat
                    .format(curtDate) + " 00:00:00");
        } catch (ParseException e) {
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curtDate);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        curtDate = calendar.getTime();
        return curtDate;
    }

    public synchronized static Date getNextMonthFirstDay(Date curtDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curtDate);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        curtDate = calendar.getTime();
        return curtDate;
    }

    public synchronized static Date getThisWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime(); // 周一时间
    }

    public synchronized static Date getThisWeekMonday() {
//		Date date = new Date();
        Calendar cal = Calendar.getInstance();
//		cal.setTime(date);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime(); // 周一时间
    }

    // 获取指定日期所在月的第一天：
    public synchronized static Date getThisMonthFirstDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return cal.getTime();
    }

    // 获取指定日期所在月的第一天：
    public synchronized static String getThisMonthFirstDay(String str) {
        Date date = null;
        try {
            date = monthDateFormat.parse(str);
        } catch (ParseException e) {
            return "";
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        Date resultDate = cal.getTime();
        return partitionDateFormat.format(resultDate);
    }

    // 获取指定日期所在月的最后一天
    public synchronized static Date getThisMonthLastDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置时间,当前时间不用设置
        calendar.setTime(date);
        // 设置日期为本月最大日期
        calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
        // 打印
        return calendar.getTime();
    }

    public synchronized static Date getLastMonthFirstDay(Date date) {
        Calendar cal_1 = Calendar.getInstance();// 获取当前日期
        cal_1.setTime(date);
        cal_1.add(Calendar.MONTH, -1);
        cal_1.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return cal_1.getTime();
    }

    // 获取前月第一天：
    public synchronized static Date getLastMonthFirstDay() {
        Calendar cal_1 = Calendar.getInstance();// 获取当前日期
        cal_1.add(Calendar.MONTH, -1);
        cal_1.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return cal_1.getTime();
    }

    public synchronized static Date getLastMonthLastDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 0);
        return cal.getTime();
    }

    // 获取前月的最后一天
    public synchronized static Date getLastMonthLastDay() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 0);
        return cal.getTime();
    }

    // 获取当前月第一天：
    public synchronized static Date getThisMonthFirstDay() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);// 设置为1号,当前日期既为本月第一天
        return cal.getTime();

    }

    // 获取当前月的最后一天
    public synchronized static Date getThisMonthLastDay() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }

    public synchronized static Date getNextWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, 7);
        return cal.getTime();
    }

    public synchronized static int getYear(Date curtDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curtDate);
        calendar.add(Calendar.YEAR, 0);
        curtDate = calendar.getTime();
        return calendar.getWeekYear();
    }

    /**
     * 获取当自然周
     *
     * @param curtDate
     * @return
     */
    public synchronized static int getWeek(Date curtDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(curtDate);
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }

    public static synchronized Date getWholeHourStartDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        cal.add(Calendar.HOUR, -1);
        return cal.getTime();
    }

    public static synchronized String formatDate(DateFormat dateFormat, String dateStr) {
        return dateFormat.format(parseDateStringTwice(dateStr));
    }


    public synchronized static Date getOffsetYearDate(Date date, int offsetYear) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, offsetYear);
        return calendar.getTime();
    }

    public synchronized static boolean equals(Date date1, Date date2) {
        if (date1 == null) {
            return date2 == null;
        } else {
            return date2 == null ? false : date1.compareTo(date2) == 0;
        }
    }

    public static class RecentDate {
        private String recentDay;
        private Date startDate;
        private Date endDate;

        public RecentDate(String recentDay, Date startDate, Date endDate) {
            this.recentDay = recentDay;
            this.startDate = startDate;
            this.endDate = endDate;
        }

        public String getRecentDay() {
            return recentDay;
        }

        public void setRecentDay(String recentDay) {
            this.recentDay = recentDay;
        }

        public Date getStartDate() {
            return startDate;
        }

        public void setStartDate(Date startDate) {
            this.startDate = startDate;
        }

        public Date getEndDate() {
            return endDate;
        }

        public void setEndDate(Date endDate) {
            this.endDate = endDate;
        }
    }

    /*
     * 将时间戳转换为时间
     */
    public synchronized static String stampToDate(String s) {
        String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        long lt = new Long(s);
        Date date = new Date(lt);
        res = simpleDateFormat.format(date);
        return res;
    }

    public synchronized static String getCurrentTimeStr() {
        return preciseDateFormat.format(new Date());
    }

    public synchronized static String getDateRangeString(Date startDate, Date endDate) {
        String result = "";
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        if (startDate != null && endDate != null) {
            String startString = df.format(startDate);
            String endString = df.format(endDate);
            result = startString + "~" + endString;
        }
        return result;
    }

    public synchronized static boolean isValidDate(String str) {
        int length = str.length();
        DateFormat format;
        if (7 == length) {
            format = monthDateFormat;
        } else {
            format = partitionDateFormat;
        }
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写；
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }


    public synchronized static Date getOffsetHourDate(Date date, int offsetHour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, offsetHour);
        return calendar.getTime();
    }


    public synchronized static String formatUtcToGmtDate(Date date) {
        return dayGMTDateFormat.format(getOffsetHourDate(date, -8));
    }

}
